﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using LiquidMeasure.Properties;
using LiquidMeasure;
using Utility;
using System.Diagnostics;
using System.IO;
using System.Data;
using System.Configuration;
using System.Windows.Interop;
using System.Drawing;

namespace LiquidMeasure
{
    /// <summary>
    /// Interaction logic for Measure.xaml
    /// </summary>
    public partial class MeasureWindow : UserControl
    {
        MyVisualHost visualHost;
        CalibStage curStage = CalibStage.Init;
        
        public delegate void Finish(bool allfinished);
        public event Finish onFinished;
        VideoSnapShot videoSnapShot;
        static public List<List<MeasureInfo>> allMeasureInfos = new List<List<MeasureInfo>>();
        public MeasureWindow()
        {
            InitializeComponent(); 
            this.AdjustSize();
          
            this.Loaded += new RoutedEventHandler(MeasureWindow_Loaded);

            SetInfo("如果自动标示液面不准确，请拖动Mark进行手动标定。");
        }

        void MeasureWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (videoSnapShot == null)
            {
                videoSnapShot = new VideoSnapShot(sourcePlayer);
                videoSnapShot.StartCapture();
            }

            AcquireBackImage();
            myCanvas.Children.Clear();
            visualHost = new MyVisualHost(true, GlobalVals.samplesThisBatch);
            SetStage(curStage);
            myCanvas.Children.Add(visualHost);

            if( GlobalVals.curBatch == 1)
                visualHost.onPositionChanged += new MyVisualHost.PositionChanged(visualHost_onPositionChanged);
        }

        private void AcquireBackImage()
        {
            //throw new NotImplementedException();
        }

        private void AdjustSize()
        {
            this.Height = double.NaN;
            this.Width = double.NaN;
        }

        private void SetInfo(string s)
        {
            txtInfo.Text = s;
        }

        private void SetStage(CalibStage calibStage)
        {
            curStage = calibStage;
            visualHost.Stage = curStage;
            myCanvas.InvalidateVisual();
        }

        void visualHost_onPositionChanged()
        {
            this.Dispatcher.BeginInvoke(
              (Action)delegate()
              {
                  //Update code goes in here
                  myCanvas.InvalidateVisual();
                  List<double> highMarkers = visualHost.GetVisualHeights(stringRes.HighMarker);
                  List<double> lowMarkers = visualHost.GetVisualHeights(stringRes.LowMarker);
                  List<MARKER_POS> markerPositions = new List<MARKER_POS>();
                  for (int i = 0; i < highMarkers.Count; i++)
                  {
                      markerPositions.Add(new MARKER_POS(highMarkers[i],lowMarkers[i]));
                  }
                  UpdateListView(markerPositions,false);
              });
        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            List<double> highMarkers = visualHost.GetVisualHeights(stringRes.HighMarker);
            List<double> lowMarkers = visualHost.GetVisualHeights(stringRes.LowMarker);
            List<MARKER_POS> markerPositions = new List<MARKER_POS>();
            List<MeasureInfo> measureInfos = new List<MeasureInfo>();
            for (int i = 0; i < highMarkers.Count; i++)
            {
                markerPositions.Add(new MARKER_POS(highMarkers[i], lowMarkers[i]));
            }
            string[] barcodes = InputBarcode.Barcodes[GlobalVals.curBatch - 1].ToArray();
            for (int i = 0; i < barcodes.Length; i++)
            {
                double h = Convert2RealCoordFromCurrentUI(markerPositions[i].high);
                double l = Convert2RealCoordFromCurrentUI(markerPositions[i].low);
                double hLen = CalculateValue(h, i);
                double lLen = CalculateValue(l, i);
                double hVol = CalculateValue(h, i,false);
                double lVol = CalculateValue(l, i, false);
                measureInfos.Add(new MeasureInfo(barcodes[i],hLen, lLen, hVol, lVol));
            }
            allMeasureInfos.Add(measureInfos);

            onFinished( GlobalVals.curBatch * GlobalVals.maxSamplesPerBatch >= GlobalVals.totalSample);
            
        }

        private double Convert2RealCoordFromCurrentUI(double pixel)
        {
            return Calib.yShift + pixel / Calib.ratio;
        }
        private void DoMeasure()
        {
            string sExeFolder = Utility.Calib.GetExeFolder();
            string sResult = sExeFolder + "\\Temp\\result.txt";
            if (File.Exists(sResult))
                File.Delete(sResult);

            string sImagePath = sExeFolder + "\\Temp\\last.jpg";
            string sArgs = string.Format("shark@ {0} {1}", sImagePath, GlobalVals.samplesThisBatch);
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = sExeFolder + "SliceMarker.exe";
            info.Arguments = sArgs;
            info.WindowStyle = ProcessWindowStyle.Minimized;
            Process pro = Process.Start(info);
            pro.WaitForExit();

            if (!File.Exists(sResult))
            {
                SetInfo("标定图像液面失败，请检查log文件！");
                return;
            }

            List<MARKER_POS> markPositions = new List<MARKER_POS>();
            using (StreamReader sr = new StreamReader(sResult))
            {
                string sTmp = "";
                while ((sTmp = sr.ReadLine()) != null)
                {
                    string[] results = sTmp.Split(' ');
                    int high = int.Parse(results[0]);
                    int low = int.Parse(results[1]);
                    markPositions.Add(new MARKER_POS(high, low));
                    if (markPositions.Count == GlobalVals.samplesThisBatch)
                        break;
                }
            }
            MyVisualHost visualHost = (MyVisualHost)myCanvas.Children[0];
            visualHost.SetMarkerPositions(markPositions);
            UpdateListView(markPositions);
            myCanvas.InvalidateVisual();
        }

        private void UpdateListView(List<MARKER_POS> markPositions,bool bFromMarkSliceExe = true)
        {
            DataTable tbl = new DataTable("result");
            tbl.Columns.Add("TubeID", typeof(string));
            tbl.Columns.Add("Z1", typeof(string));
            tbl.Columns.Add("Z2", typeof(string));
            
            for (int i = 0; i < markPositions.Count; i++)
            {
                double h, l;
                h = Convert2RealCoordFromSliceMarker(markPositions[i].high,i);
                l = Convert2RealCoordFromSliceMarker(markPositions[i].low, i);
                if (!bFromMarkSliceExe)
                {
                    h = Convert2RealCoordFromCurrentUI(markPositions[i].high);
                    l = Convert2RealCoordFromCurrentUI(markPositions[i].low);
                }
                double hLen = CalculateValue(h,i);
                double lLen = CalculateValue(l, i);
                tbl.Rows.Add((i + 1).ToString(), hLen.ToString("0.00"),lLen.ToString("0.00"));
            }
            lstviewResult.ItemsSource = tbl.DefaultView;
 
        }


        //从SlickMark计算出的像素位置计算出该像素在图像中的绝对坐标
        private double Convert2RealCoordFromSliceMarker(double pixelFromSubTop, int tubeID)
        {
            double subTop = Calib.yShift + Calib.Instance.roiList[tubeID].ptStart.Y / Calib.ratio;
            double pixelRealCoord = subTop + pixelFromSubTop;
            return pixelRealCoord;
        }


        //get read coordination for the calibration mark
        private double GetRealCoord(double markPos)
        {
            return Calib.yShift + markPos / Calib.ratio;
        }

        private double CalculateValue(double pixelPos,int tubeID, bool length = true)
        {
            double lowCalib = GetRealCoord(Calib.Instance.calibPositions[tubeID].low);
            double curMarkLen = lowCalib - pixelPos;
            double highCalib2LowCalibLen = lowCalib - GetRealCoord(Calib.Instance.calibPositions[tubeID].high);
            double Vh = Calib.Instance.highHeight;
            double Vl = Calib.Instance.lowHeight;

            if (!length) //calculate volume
            {
                Vh = Calib.Instance.highVolume;
                Vl = Calib.Instance.lowVolume;

            }
            double Vx = Vl + (Vh - Vl) * curMarkLen / highCalib2LowCalibLen;
            return Vx;
        }
        private void btnMeasure_Click(object sender, RoutedEventArgs e)
        {
            EnableButtons(false);
            DoMeasure();
            EnableButtons(true);
        }

        private void EnableButtons(bool bEnable)
        {
            btnMeasure.IsEnabled = bEnable;
            btnNext.IsEnabled = bEnable;
            btnRefresh.IsEnabled = bEnable;
            
        }

        public void StopCamera()
        {
            if (sourcePlayer.IsRunning)
            {
                sourcePlayer.SignalToStop();
                sourcePlayer.WaitForStop();
            }
        }


        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            IntPtr hbitmap = videoSnapShot.GetImage();
            var handle = new SafeHBitmapHandle(hbitmap, true); 
            using (handle)
            {
                BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(),
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());

                string sSaveFolder = Helper.GetSaveFolder();
                string[] jpgFiles = Directory.EnumerateFiles(sSaveFolder, "*.jpg").ToArray();
                string sCurImg = sSaveFolder + string.Format("{0}.jpg",jpgFiles.Length + 1);
                using (var fileStream = new FileStream(sCurImg, FileMode.Create))
                {
                    JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
                    encoder.Save(fileStream);
                }
            }

        }


        public struct MeasureInfo
        {
            public string sBarcode;
            public double Z1;
            public double Z2;
            public double highVol;
            public double lowVol;
            public MeasureInfo(string barcode,double z1, double z2, double hV, double lV)
            {
                sBarcode = barcode;
                Z1 = z1;
                Z2 = z2;
                highVol = hV;
                lowVol = lV;
            }
        }


    }
}
